package com.accp.ssmoa.shiro;

import java.util.List;

import javax.annotation.Resource;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;
import org.springframework.stereotype.Service;

import com.accp.ssmoa.pojo.Menu;
import com.accp.ssmoa.pojo.Role;
import com.accp.ssmoa.pojo.User;
import com.accp.ssmoa.service.ShiroService;


@Service("shiroDbRealm")
public class ShiroDbRealm extends AuthorizingRealm {
	
	@Resource(name="shiroService")
	private ShiroService shiroService;

	//身份认证
	@Override
	protected AuthenticationInfo doGetAuthenticationInfo(
			AuthenticationToken token) throws AuthenticationException {

		//1.把AuthenticationToken转换为UsernamePasswordToken
		UsernamePasswordToken upToken=(UsernamePasswordToken)token;
		
		//2.从UsernamePasswordToken获取username和password
		
		String username=upToken.getUsername();
		
		
		//3.调用数据库的方法，从数据库中查询username对应的用户记录
		User user=shiroService.getUserByUserName(username);

		//4、判断并抛异常
        if (user == null) {
            // 抛出 帐号找不到异常
            throw new UnknownAccountException();
        }
        // 判断帐号是否锁定
        if (user.getStatus().equalsIgnoreCase("0")) {
            // 抛出 帐号锁定异常
            throw new LockedAccountException();
        }
		
		//5.根据用户的情况，来构建AuthenticationInfo 对象并返回,通常使用的实现类为：SimpleAuthenticationInfo
		//以下信息是从数据库中获取的
		//1、principal：认证的实体类信息，可以是username，也可以是数据表对应的用户的实体类对象		
		Object principal=user;
		
		//2、credentials：密码
		Object credentials=user.getPassword();
		
		//3、realmName:当前realm对象的name，调用父类的getName()方法即可
		String realmName=getName();
		
		
		//4、盐值,盐值为唯一的字符串，通常使用 用户名来作为盐值
		ByteSource credentialsSalt=ByteSource.Util.bytes(username);
		
		SimpleAuthenticationInfo info=
				new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName);
		
		
		return info;
	
	}

	//授权
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		
		//1.从PrincipalCollection中获取登录用户的信息
		User user=(User)principals.fromRealm(getName()).iterator().next();
		
		user=shiroService.getUserById(user.getId());
		//2.利用登录用户的信息来获取当前用户的角色或权限
		List<Menu> permissions=user.getMenus();
		List<Role> roles=user.getRoles();
		
		
		//3.创建SimpleAuthorizationInfo,并设置其角色roles和权限permissions
		SimpleAuthorizationInfo info=new SimpleAuthorizationInfo();
		
		for (Role role : roles) {
			info.addRole(role.getName());
		}
		for (Menu permission : permissions) {
			info.addStringPermission(permission.getPermission());
		}
		
		
		//4.返回SimpleAuthorizationInfo对象

		return info;
	}

}
